﻿using System;
using System.Linq;
using System.Text;
using System.Collections.Generic;
using System.Data;
using System.Data.SqlClient;
using CommonTools;
using shop.Model;


namespace shop.Bll
{

	/// <summary>  </summary>
  	public abstract class MyDocBaseBll<T> : DocBaseBll<T>
         where T: class, IDoc, new()
  	{


        #region 查询方法: 按照 id,编号, 日期...


        public override T GetDoc(int id)
        {
            if (id == 0) return null;

            T doc = DB.FSql.Select<T>()
                .Where(this.WhereExp)
                .WhereIf(true, "\"Isdel\" = 0")
                .FirstOrDefault(a => a.DocId == id); 

            if (doc == null)
            {
                return null;
            }

            doc.ReadTime = DB.FSql.GetTime();
            return doc;
        }




       
        public override DocStatus GetStatus(T doc)
        {
            DocStatus s = new DocStatus();
            if (doc == null || doc.DocId ==0)
            {
                return s;
            }

            int id = doc.DocId;


            var rst = DB.FSql.Select<T>()
                .Where(this.WhereExp)
                .WhereIf(true, "\"Isdel\" = 0")
                .Where(a => a.DocId == id)
                .ToOne(a => new { a.IsChecked });


            if (rst == null )
            {
                s.Reason = Model.CN.Msg_DocDeleted;  // "单据已经删除";
                s.EnableDelete = false;
                s.EnableModify = false;
            }
            else if (rst.IsChecked > 0)
            {
                s.Reason = Model.CN.Msg_DocCheckedCannotModify;   // "单据已经审核,不能修改";
                s.EnableModify = false;
                s.EnableDelete = false;
            }
            else
            {
                s.Reason = "";
                s.EnableDelete = s.EnableModify = true;
            }

            return s;

        }

        /// <summary> 本单据附加的查询条件, (除了isdel=0之外其他的条件, 比如: docType='单据类型') </summary>
        public virtual System.Linq.Expressions.Expression<Func<T, bool>> WhereExp { set; get; }


        public override IEnumerable<T> Query(DateTime? begin, DateTime? end, string keyWord, QueryDateEnum dateEnum = QueryDateEnum.OccurDate, params string[] args)
        {
            var rst = DB.FSql.Select<T>()
                .Where(WhereExp)
               .WhereIf(true, "\"Isdel\" = 0");

            if (string.IsNullOrEmpty(keyWord) == false)
            {
                rst = rst.Where(a => a.Number.Contains(keyWord));
            }

            //日期条件
            if (begin.HasValue && end.HasValue)
            {
                switch (dateEnum)
                {
                    case QueryDateEnum.PreparedDate:
                        rst = rst.Where(a => a.PreparedDate >= begin && a.PreparedDate <= end);
                        break;
                    case QueryDateEnum.OccurDate:
                        rst = rst.Where(a => a.OccurDate >= begin && a.OccurDate <= end);
                        break;
                    default:
                        rst = rst.Where(a => a.OccurDate >= begin && a.OccurDate <= end);
                        break;
                }
            }

            List<T> list = rst.OrderByDescending(a=> a.DocId).Take(50).ToList();    //最多50个

            if (list.Count ==0)
            {
                //如果没有放宽条件
                rst = DB.FSql.Select<T>()
                    .Where(this.WhereExp)
                    .WhereIf(true, "\"Isdel\" = 0 ");

                if (string.IsNullOrEmpty(keyWord) == false)
                {
                    rst = rst.Where(a => a.Number.Contains(keyWord));
                }

                list = rst.OrderByDescending(a=> a.DocId).Take(50).ToList();    //最多50个
            }

            DateTime time = DB.FSql.GetTime();  //获取服务器时间作为单据的读取时间

            foreach (T doc in list)
            {
                doc.ReadTime = time;
            }
            return list;

        }

        public override IEnumerable<T> Query(string num)
        {
            return Query(null, null, num) as List<T>;
        }


		/// <summary>
        /// 按照编号查询合同, 只返回一个结果
        /// </summary>
        public virtual T GetDocByNum(string num)
        {
            return DB.FSql.Select<T>()
                .Where(this.WhereExp)
                .WhereIf(true, "\"Isdel\" = 0 ")
                .Where(a => a.Number == num)
                .ToOne();
        }

        /// <summary> 创建单据 </summary>
        public override T CreateDoc()
        {
            return new T() ;
        }

        #endregion



        /// <summary> 删除单据 </summary>
        public override bool Delete(T doc, IUser user, out string err)
        {
            if (doc == null)
            {
                err = Model.CN.Msg_Dociswrong;
                return false;
            }
            if (doc.DocId == 0)
            {
                err = Model.CN.Msg_QueryBeforeModify;
                return false;
            }

			//检查权限, 
            if (UserBll.CheckRight(this.SavePermission) == false)
            {
				err = Model.CN.Msg_NoRightToDelete;  // "对不起,您无权限删除单据!";
                return false;
            }
            if (doc.PreparedBy != user.Name && UserBll.CheckRight(this.ModifyPermission) == false)
            {
				err = Model.CN.Msg_NoRightToModifyOther;   //"对不起,您无权限修改他人单据!";
                return false;
            }

			//检查单据状态
            DocStatus status = GetStatus(doc);
            if (status.EnableDelete)
            {
                //DB.FSql.Update<T>()
                //    .SetSource(doc)
                //    .UpdateColumns(new string[] { "Isdel", "IsdelDate" })
                //    .ExecuteAffrows();


                var time = DB.FSql.GetTime();

                DB.FSql.Update<T>()
                    .Where(doc)
                    .Set(a => new { Isdel = true, IsdelDate = time })
                    .ExecuteAffrows();

                //日志
                DB.FSql.Insert(new CLogs(doc, user, "删除", $"删除编号:{doc.Number}, id:{doc.DocId}")).ExecuteAffrows();

                //正在编辑
                DB.FSql.Delete<Editings>().Where(a => a.DocId == doc.DocId && a.DocName == this.DocFlag).ExecuteAffrows();

                doc.OnDocDeleted();

                err = "";
                return true;
            }
            else
            {
                err = status.Reason;
                return false;
            }

        }


		/// <summary> 保存,修改 </summary>
        public override bool Save(T doc, IUser user, out string err)
        {
            err = "";
            if (doc == null)
            {
				err = Model.CN.Msg_SystemError;  // "系统错误, 请联系管理员!";
                return false;
            }

            if (err !="")
            {
                return false;   
            }


            if (doc.DocId == 0)
            {
				if (UserBll.CheckRight(this.SavePermission) == false)
                {
                    err = Model.CN.Msg_NoRightToSaveDoc;   // "对不起,您无权限保存单据!";
                    return false;
                }

                //保存新单据

                //doc.Number = GetNewNum == null
                //    ? NumberHelper.GetMaxIntNum(doc.DocFlag).ToString() 
                //    : GetNewNum.Invoke();

                if (GetNewNum != null)
                {
                    doc.Number = GetNewNum.Invoke(doc);
                }
                else
                {
                    doc.Number = NumberHelper.GetMaxIntNum(doc.DocFlag).ToString();
                }


                doc.PreparedBy = user.Name;

                var time = DB.FSql.GetTime();
                doc.LastModifyTime = doc.ReadTime = doc.PreparedDate = time;

                var id = DB.FSql.Insert(doc).ExecuteIdentity();
                doc.DocId = (int)id;

                //表体
                SaveItems(doc, time);

                //日志
                DB.FSql.Insert(new CLogs(doc, user, "保存", $"保存编号:{doc.Number},id:{doc.DocId}")).ExecuteAffrows();
                 
                err = Model.CN.Msg_Save;  // "保存成功!";
                doc.OnDocSaved();           //触发保存事件

                return true;
            }
            else
            {
				//检查权限 不是自己的单据需要额外的权限
                if (doc.PreparedBy != user.Name && UserBll.CheckRight(this.ModifyPermission)== false)
                {
                    err = Model.CN.Msg_NoRightToModifyOther;   // "对不起,您无权限修改他人单据!";
                    return false;
                }

                //修改 
                DocStatus ds = GetStatus(doc);  //检查单据状态

                if (ds.EnableModify == false)
                {
                    err = ds.Reason;
                    return false;
                }


                var time = DB.FSql.GetTime();
                doc.LastModifyTime = doc.ReadTime = time;
                doc.PreparedBy = user.Name;

                var ignoreColumns = new[]
                {
                    nameof(doc.PreparedDate),
                    "Isdel" , 
                    nameof(doc.IsChecked),
                    "IsCheckStatus",
                    "IsCheckDate" 
                };   

                DB.FSql.Update<T>()
                    .SetSource(doc)
                    .IgnoreColumns(ignoreColumns)
                    .ExecuteAffrows();

                //表体
                SaveItems(doc, time);

                //日志
                DB.FSql.Insert(new CLogs(doc, user, "修改", $"修改,编号:{doc.Number}, id:{doc.DocId} ")).ExecuteAffrows();

                //正在编辑
                DB.FSql.Delete<Editings>().Where(a => a.DocId == doc.DocId && a.DocName == this.DocFlag).ExecuteAffrows();

                err = Model.CN.Msg_Save;  // "保存成功!";
                doc.OnDocSaved();           //触发保存事件

                return true;
         
 
            }


        }


        ///// <summary> 获取最大编号 </summary>
        //public virtual Func<string> GetNewNum { get; }


        /// <summary> 获取最大编号 , 需要提供单据参数 </summary>
        public virtual Func<T, string> GetNewNum { get; }
        


        /// <summary> 保存表体 </summary>
        public abstract void SaveItems(T doc, DateTime time);

         


    }

}



 
